package com.hanserwei.mydemo.hiorder;

import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.*;

public class SimpleStream<T> {
    private Collection<T> collection;

    private SimpleStream(Collection<T> collection) {
        this.collection = collection;
    }

    public static void main(String[] args) {
        List<Integer> list = List.of(1, 2, 3, 4, 5, 6, 7, 1, 2, 3);
        HashSet<Integer> collect = SimpleStream.of(list).collect(HashSet::new, HashSet::add);
        System.out.println(collect);
        StringBuilder collect1 = SimpleStream.of(list).collect(StringBuilder::new, StringBuilder::append);
        System.out.println(collect1.toString());
        StringJoiner collect2 = SimpleStream.of(list).collect(() -> new StringJoiner("_"), (joiner, t) -> joiner.add(String.valueOf(t)));
        System.out.println(collect2.toString());
        StringJoiner collect3 = SimpleStream.of(list).map(String::valueOf).collect(() -> new StringJoiner("-"), StringJoiner::add);
        System.out.println(collect3);
        HashMap<Integer, Integer> collect4 = SimpleStream.of(list).collect(HashMap::new, (HashMap<Integer, Integer> map, Integer t) -> {
            if (!map.containsKey(t)) {
                map.put(t, 1);
            } else {
                map.put(t, map.get(t) + 1);
            }
        });
        System.out.println(collect4);
        HashMap<Integer, Integer> collect5 = SimpleStream.of(list).collect(HashMap::new, (map, t) -> {
            if (!map.containsKey(t)) {
                map.put(t, 1);
            } else {
                map.put(t, map.get(t) + 1);
            }
        });
        System.out.println(collect5);
        /*
            computeIfAbsent方法
            如果key在map中不存在，将key连同新生成的value值存入map，并返回value值。
            如果key在map中存在，会返回此key上次的value值。
         */
        HashMap<Integer, AtomicInteger> collect6 = SimpleStream.of(list).collect(HashMap::new, (map, k) -> map.computeIfAbsent(k, v -> new AtomicInteger()).getAndIncrement());
        System.out.println(collect6);
    }

    /**
     * 从提供的集合创建一个新的 {@code SimpleStream} 实例。
     *
     * @param <T>        集合中元素的类型
     * @param collection 用作 {@code SimpleStream} 源的集合
     * @return 包含所提供集合元素的新 {@code SimpleStream} 实例
     */
    public static <T> SimpleStream<T> of(Collection<T> collection) {
        return new SimpleStream<>(collection);
    }


    /**
     * 使用提供的供应商和消费者对流中的元素进行收集操作。
     *
     * @param <C>      收集容器的类型
     * @param supplier 用于创建新的收集容器的供应商
     * @param consumer 用于将元素添加到收集容器的消费者
     * @return 包含所有流元素的收集容器
     */
    public <C> C collect(Supplier<C> supplier, BiConsumer<C, T> consumer) {
        C c = supplier.get();
        for (T t : collection) {
            consumer.accept(c, t);
        }
        return c;
    }

    /**
     * 使用提供的二元操作符对流中的元素进行归约操作。
     *
     * @param operator 用于合并元素的二元操作符
     * @param o        归约操作的初始值
     * @return 归约操作的结果
     */
    public T reduce(BinaryOperator<T> operator, T o) { // o代表p的初值
        T p = o; // 上次合并的结果
        for (T t : collection) { // t 本次遍历的元素
            p = operator.apply(p, t);
        }
        return p;
    }

    /**
     * 根据给定的谓词过滤流中的元素。
     *
     * @param predicate 用于测试元素是否应包含在结果中的谓词
     * @return 一个包含满足谓词条件的元素的新 {@code SimpleStream} 实例
     */
    public SimpleStream<T> filter(Predicate<T> predicate) {
        List<T> result = new ArrayList<>();
        for (T t : collection) {
            if (predicate.test(t)) {
                result.add(t);
            }
        }
        return new SimpleStream<>(result);
    }

    /**
     * 将流中的每个元素应用给定的函数进行转换。
     *
     * @param <U>      转换后元素的类型
     * @param function 应用于每个元素的函数
     * @return 一个包含转换后元素的新 {@code SimpleStream} 实例
     */
    public <U> SimpleStream<U> map(Function<T, U> function) {
        List<U> result = new ArrayList<>();
        for (T t : collection) {
            U u = function.apply(t);
            result.add(u);
        }
        return new SimpleStream<>(result);
    }

    /**
     * 对流中的每个元素执行给定的操作。
     *
     * @param consumer 对每个元素执行的操作
     */
    public void forEach(Consumer<T> consumer) {
        for (T t : collection) {
            consumer.accept(t);
        }
    }
}
